package com.fruit.service.lightpay.impl;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.fruit.constants.LightPayConstant;
import com.fruit.constants.PayConstant;
import com.fruit.mapper.lightpay.LightPayMapper;
import com.fruit.mapper.sys.SysMapper;
import com.fruit.pojo.lightpay.LightPayCashier;
import com.fruit.pojo.lightpay.LightPayCashierAlipay;
import com.fruit.pojo.lightpay.LightPayCashierWechat;
import com.fruit.pojo.pay.TransactionFlow;
import com.fruit.pojo.sys.AlipayConfig;
import com.fruit.pojo.sys.WechatConfig;
import com.fruit.service.lightpay.LightPayManager;
import com.fruit.service.pay.PayManager;
import com.fruit.util.CommonUtil;
import com.fruit.util.CustomUtil;
import com.fruit.util.DateUtil;
import com.fruit.util.HttpClientManagerT;
import com.fruit.util.RequestHandler;
import com.fruit.util.ResultInfo;
import com.fruit.util.ResultUtil;

import lombok.extern.slf4j.Slf4j;

/**
 * LightPayService
 *
 * @author shibeilei
 * @version 2017.12.06 11:23
 */
@Slf4j
@Service
public class LightPayService implements LightPayManager {

	@Autowired
	private PayManager payService;

	@Autowired
	private SysMapper sysMapper;

	@Autowired
	private LightPayMapper lightPayMapper;

	@Value("${alipay.money}")
	private String alipayMoney;

	@Value("${wechat.money}")
	private String xwMoney;

	@Value("${domain}")
	private String domain;
	
	@Value("${h5_domain}")
	private String h5Domain;
	
	@Value("${project.name}")
	private String projectName;
	

	@Override
	public Map<String, Object> getTransactionFlow(String tradeId, String transactionCode) {
		Map<String, Object> resMap = new HashMap<String, Object>();
		log.info("[{}]-【查看交易流水】-【开始】", tradeId);
		try {
			TransactionFlow tf = payService.getTransactionFlow(transactionCode);

			if (tf == null) {
				resMap.put("result", ResultUtil.initResult(ResultInfo.ERROR, "error", "交易订单不存在"));
				return resMap;
			}
			if (!PayConstant.State.notpay.equals(tf.getState())) {
				resMap.put("result", ResultUtil.initResult(ResultInfo.ERROR, "error", "交易订单已取消或已支付"));
				return resMap;
			}

			resMap.put("price", tf.getPayPrice());
			resMap.put("transactionCode", transactionCode);
			resMap.put("result", ResultUtil.initResult(ResultInfo.SUCCESS, "OK", "查询成功"));
			return resMap;
		} finally {
			ResultInfo ri = (ResultInfo) resMap.get("result");
			if (ResultInfo.ERROR.equals(ri.getState())) {
				log.error("[{}]-【查看交易流水】-【异常】-【{}：{}】", tradeId, ri.getCode(), ri.getMessage());
			} else {
				log.info("[{}]-【查看交易流水】-【成功】", tradeId);
			}
			log.info("[{}]-【查看交易流水】-【结束】", tradeId);
		}

	}

	/**
	 * 校验参数
	 *
	 * @param lpc
	 *            收银记录
	 * @return 返回校验结果
	 */
	public Map<String, Object> validation(LightPayCashier lpc) {
		Map<String, Object> resMap = new HashMap<String, Object>();
		if (StringUtils.isEmpty(lpc.getTransactionCode())) {
			resMap.put("result", ResultUtil.initResult(ResultInfo.ERROR, "error", "参数有误"));
			return resMap;
		}

		int userId = lpc.getUserId();
		if (userId <= 0) {
			resMap.put("result", ResultUtil.initResult(ResultInfo.ERROR, "error", "用户不存在"));
			return resMap;
		}

		// 验证金额
		if (lpc.getPrice() == null || lpc.getPrice().compareTo(BigDecimal.ZERO) <= 0) {
			resMap.put("result", ResultUtil.initResult(ResultInfo.ERROR, "error", "支付金额有误"));
			return resMap;
		}

		TransactionFlow tf = payService.getTransactionFlow(lpc.getTransactionCode());

		if (tf == null) {
			resMap.put("result", ResultUtil.initResult(ResultInfo.ERROR, "error", "交易订单不存在"));
			return resMap;
		}
		if (!PayConstant.State.notpay.equals(tf.getState())) {
			resMap.put("result", ResultUtil.initResult(ResultInfo.ERROR, "error", "交易订单已取消或已支付"));
			return resMap;
		}
		if (lpc.getPrice().compareTo(tf.getPayPrice()) != 0) {
			resMap.put("result", ResultUtil.initResult(ResultInfo.ERROR, "error", "支付金额有误"));
			return resMap;
		}

		LightPayCashier lpcnew = lightPayMapper.getLightpayCashierByTCode(tf.getCode());
		if (lpcnew != null && !PayConstant.State.notpay.equals(lpcnew.getState())) {
			resMap.put("result", ResultUtil.initResult(ResultInfo.ERROR, "error", "交易订单已取消或已支付"));
			return resMap;
		}

		String curTime = DateUtil.getTime();
		if (lpcnew != null) {
			lpc.setId(lpcnew.getId());
			lpc.setRemark(lpcnew.getRemark());
			lpc.setCode(lpcnew.getCode());
		} else {
			// 插入收银记录
			lpc.setRemark(tf.getRemark());
			lpc.setCreateTime(curTime);
			lpc.setState(PayConstant.State.notpay.getValue());
			lightPayMapper.saveLightpayCashier(lpc);
			lpc.setCode(CustomUtil.orderCode(3, lpc.getId(), lpc.getUserId()));
			int num = lightPayMapper.updateLightpayCashierCode(lpc);
			if (num != 1) {
				resMap.put("result",
						ResultUtil.initResult(ResultInfo.ERROR, "confirm_again", "请重新结算!", null, ResultInfo.ROLLBACK));
				return resMap;
			}
		}
		resMap.put("tf", tf);
		resMap.put("result", ResultUtil.initResult(ResultInfo.SUCCESS, "OK", "校验成功"));

		return resMap;

	}

	@Override
	public Map<String, Object> saveAlipayPayCashier(String tradeId, LightPayCashier lpc) {
		log.info("[{}]-【支付宝支付】-【交易流水号：{}】-【用户：{}】-【开始】", tradeId, lpc.getTransactionCode(), lpc.getUserId());
		Map<String, Object> resMap = new HashMap<String, Object>();
		try {
			// 验证参数
			log.info("[{}]-【支付宝支付】-【验证参数】", tradeId);
			lpc.setPayMode(PayConstant.PayMode.alipay.getValue());
			resMap = validation(lpc);
			ResultInfo ri = (ResultInfo) resMap.get("result");
			if (ResultInfo.ERROR.equals(ri.getState())) {
				return resMap;
			}
			AlipayConfig ac = sysMapper.getAlipayConfig();
			if (ac == null) {
				resMap.put("result", ResultUtil.initResult(ResultInfo.ERROR, "error", "系统异常"));
				return resMap;
			}
			log.info("[{}]-【支付宝支付】-【生成记录】", tradeId);
			LightPayCashierAlipay lpca = new LightPayCashierAlipay();

			lpca = new LightPayCashierAlipay();
			lpca.setCashierId(lpc.getId());
			if (PayConstant.PayValue.test.equals(ac.getPayValue())) {
				lpca.setTotalAmount(alipayMoney);
			} else {
				lpca.setTotalAmount(lpc.getPrice().toString());
			}
			lpca.setTimeStart(lpc.getCreateTime());
			lpca.setSellerId(ac.getSellerId());

			log.info("[{}]-【支付宝支付】-【封装支付宝参数】", tradeId);
			Map<String, String> returnParams = new HashMap<String, String>();
			returnParams.put("outTradeNo", lpc.getCode());
			returnParams.put("subject", lpc.getRemark());
			returnParams.put("totalAmount", lpca.getTotalAmount());
			returnParams.put("body", "共花费金额" + lpca.getTotalAmount() + "元");
			returnParams.put("appId", ac.getAppId());
			returnParams.put("returnUrl", domain + ac.getReturnUrl() + "?code=" + lpc.getCode());
			returnParams.put("notifyUrl", domain + ac.getNotifyUrl());
			returnParams.put("sellerId", ac.getSellerId());
			returnParams.put("timeOutExpress", ac.getTimeOutExpress());
			returnParams.put("alipayPublicKey", ac.getAlipayPublicKey());
			returnParams.put("appPrivateKey", ac.getAppPrivateKey());
			returnParams.put("charset", ac.getCharset());
			returnParams.put("gateWayUrl", ac.getGateWayUrl());
			resMap.put("returnParams", returnParams);
			resMap.put("result", ResultUtil.initResult(ResultInfo.SUCCESS, "OK", "保存成功"));
			log.info("支付宝支付参数为：{}", returnParams);
			return resMap;
		} finally {
			ResultInfo ri = (ResultInfo) resMap.get("result");
			if (ResultInfo.ERROR.equals(ri.getState())) {
				log.error("[{}]-【支付宝支付】-【异常】-【{}：{}】", tradeId, ri.getCode(), ri.getMessage());
			} else {
				log.info("[{}]-【支付宝支付】-【成功】", tradeId);
			}
			log.info("[{}]-【支付宝支付】-【结束】", tradeId);
		}

	}

	@Override
	public Map<String, Object> saveWechatPayCashier(String tradeId, LightPayCashier lpc) {
		log.info("[{}]-【微信支付】-【交易流水号：{}】-【用户：{}】-【开始】", tradeId, lpc.getTransactionCode(), lpc.getUserId());
		Map<String, Object> resMap = new HashMap<String, Object>();
		try {
			// 验证参数
			log.info("[{}]-【微信支付】-【验证参数】", tradeId);
			lpc.setPayMode(PayConstant.PayMode.wechat.getValue());
			resMap = validation(lpc);
			ResultInfo ri = (ResultInfo) resMap.get("result");
			if (ResultInfo.ERROR.equals(ri.getState())) {
				return resMap;
			}
			log.info("[{}]-【微信支付】-【支付渠道:{}】", tradeId, lpc.getChannelType());
			WechatConfig wc = getWechatConfig(lpc.getChannelType());
			if (wc == null) {
				resMap.put("result", ResultUtil.initResult(ResultInfo.ERROR, "error", "系统异常"));
				return resMap;
			}
			RequestHandler reqH = getReqH(wc, lpc);
			String xmlParams = reqH.parseXML();
			log.info("[{}]-【微信支付】-【生成prepay_id】-【请求参数：{}】", tradeId, xmlParams);
			String xmlRes = HttpClientManagerT.postData(HttpClientManagerT.getPostMethod(wc.getCreateOrderUrl()),
					xmlParams);
			log.info("[{}]-【微信支付】-【返回prepay_id】-【返回参数：{}】", tradeId, xmlRes);
			Map<String, String> mapRes = CommonUtil.xmlBody2map(xmlRes, "xml");
			if (mapRes == null || mapRes.isEmpty()) {
				resMap.put("result", ResultUtil.initResult(ResultInfo.ERROR, "error", "微信调用失败!"));
				return resMap;
			}
			String returnCode = mapRes.get("return_code");
			String resultCode = mapRes.get("result_code");
			if (!(PayConstant.CODE_SUCCESS.equals(returnCode) && PayConstant.CODE_SUCCESS.equals(resultCode))) {
				System.out.println(mapRes);
				resMap.put("result", ResultUtil.initResult(ResultInfo.ERROR, "error", "微信调用失败!"));
				return resMap;
			}

			log.info("[{}]-【微信支付】-【封装微信支付参数】", tradeId);
			Map<String, String> prePayInfo = getPrePayInfo(wc, mapRes, reqH);
			
			prePayInfo.put("returnUrl", domain + wc.getReturnUrl() + "?code=" + lpc.getCode());
			resMap.put("prePayInfo", prePayInfo);
			log.info("[{}]-【微信支付】-【封装微信支付参数】-【结果：{}】", tradeId, prePayInfo);
			resMap.put("result", ResultUtil.initResult(ResultInfo.SUCCESS, "OK", "保存成功"));

			return resMap;
		} finally {
			ResultInfo ri = (ResultInfo) resMap.get("result");
			if (ResultInfo.ERROR.equals(ri.getState())) {
				log.error("[{}]-【微信支付】-【异常】-【{}：{}】", tradeId, ri.getCode(), ri.getMessage());
			} else {
				log.info("[{}]-【微信支付】-【成功】", tradeId);
			}
			log.info("[{}]-【微信支付】-【结束】", tradeId);
		}
	}

	/**
	 * 返回微信配置
	 * 
	 * @param channelType 
	 * @return 微信配置
	 */
	public WechatConfig getWechatConfig(String channelType) {
		WechatConfig wc = null;
		String tradeType = "";
		if (LightPayConstant.ChannelType.APP.equals(channelType)) {
			tradeType = PayConstant.WechatPayType.APP.getValue();
		} else if (LightPayConstant.ChannelType.WAP.equals(channelType)) {
			tradeType = PayConstant.WechatPayType.JSAPI.getValue();
		} else if (LightPayConstant.ChannelType.H5.equals(channelType)) {
			tradeType = PayConstant.WechatPayType.MWEB.getValue();
		}
		wc = sysMapper.getWechatConfig(tradeType);
		if (wc != null) {
			wc.setTradeType(tradeType);
		}
		return wc;
	}

	/**
	 * 返回预支付信息
	 * @param wc 
	 * @param lpc 
	 * @return 预支付信息
	 */
	public RequestHandler getReqH(WechatConfig wc, LightPayCashier lpc) {
		RequestHandler reqH = new RequestHandler();
		reqH.setKey(wc.getApiKey());
		String totalFee = null;
		if (PayConstant.PayValue.test.equals(wc.getPayValue())) {
			totalFee = xwMoney;
		} else {
			totalFee = CustomUtil.getMoney(lpc.getPrice());
		}
		reqH.setParameters("appid", wc.getAppId());
		reqH.setParameters("mch_id", wc.getMchId());
		reqH.setParameters("nonce_str", CommonUtil.getNonceStr());
		reqH.setParameters("body", lpc.getRemark());
		reqH.setParameters("out_trade_no", lpc.getCode());
		reqH.setParameters("total_fee", totalFee);
		reqH.setParameters("spbill_create_ip", lpc.getIp());
		reqH.setParameters("notify_url", domain + wc.getNotifyUrl());
		if (PayConstant.WechatPayType.APP.equals(wc.getTradeType())) {
			reqH.setParameters("trade_type", wc.getTradeType());
		} else if (PayConstant.WechatPayType.JSAPI.equals(wc.getTradeType())) {
			reqH.setParameters("trade_type", wc.getTradeType());
			reqH.setParameters("openid", lpc.getOpenid());
		} else if (PayConstant.WechatPayType.MWEB.equals(wc.getTradeType())) {
			reqH.setParameters("trade_type", wc.getTradeType());
			Map<String, Map<String, String>> sceneInfo = new HashMap<>();
			Map<String, String> content = new HashMap<>();
			content.put("type", "Wap");
			content.put("wap_url", h5Domain);
			content.put("wap_name", projectName);
			sceneInfo.put("h5_info", content);
			reqH.setParameters("scene_info", JSON.toJSONString(sceneInfo));
		}
		return reqH;
	}

	/**
	 * 返回微信预支付信息
	 * 
	 * @param wc 
	 * @param mapRes 
	 * @return 微信预支付信息
	 */
	public Map<String, String> getPrePayInfo(WechatConfig wc, Map<String, String> mapRes, RequestHandler reqH) {
		Map<String, String> prePayInfo = new TreeMap<String, String>();
		if (PayConstant.WechatPayType.APP.equals(wc.getTradeType())) {
			prePayInfo.put("appid", wc.getAppId());
			prePayInfo.put("package", "Sign=WXPay");
			prePayInfo.put("partnerid", wc.getMchId());
			prePayInfo.put("prepayid", mapRes.get("prepay_id"));
			prePayInfo.put("timestamp", CommonUtil.getTimeStamp());
			prePayInfo.put("noncestr", CommonUtil.getNonceStr());
			String paySign = reqH.createSign(prePayInfo);
			prePayInfo.put("sign", paySign);
		} else if (PayConstant.WechatPayType.JSAPI.equals(wc.getTradeType())) {
			prePayInfo.put("appId", wc.getAppId());
			prePayInfo.put("timeStamp", CommonUtil.getTimeStamp());
			prePayInfo.put("nonceStr", CommonUtil.getNonceStr());
			prePayInfo.put("package", "prepay_id=" + mapRes.get("prepay_id"));
			prePayInfo.put("signType", "MD5");
			String paySign = reqH.createSign(prePayInfo);
			prePayInfo.put("paySign", paySign);
		} else if (PayConstant.WechatPayType.MWEB.equals(wc.getTradeType())) {
			prePayInfo.put("mweb_url", mapRes.get("mweb_url"));
		}
		return prePayInfo;
	}

	@Override
	public Map<String, Object> getLightpayCashierByCode(String code) {
		Map<String, Object> resMap = new HashMap<String, Object>();
		LightPayCashier lpc = lightPayMapper.getLightpayCashierByCode(code);
		if (lpc == null) {
			resMap.put("result", ResultUtil.initResult(ResultInfo.ERROR, "error", "收银不存在"));
			return resMap;
		}
		TransactionFlow tf = payService.getTransactionFlow(lpc.getTransactionCode());
		if (tf == null) {
			resMap.put("result", ResultUtil.initResult(ResultInfo.ERROR, "error", "交易流水不存在"));
			return resMap;
		}

		resMap.put("tf", tf);
		resMap.put("result", ResultUtil.initResult(ResultInfo.SUCCESS, "OK", "查看成功"));
		return resMap;
	}

}
